package com.haoze.nurseapp.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.haoze.common.dto.CronDescriber;
import com.haoze.common.response.Result;
import com.haoze.common.response.ResultGenerator;
import com.haoze.common.utils.CommonUtils;
import com.haoze.common.utils.CronUtil;
import com.haoze.common.utils.DateUtil;
import com.haoze.common.utils.UUIDUtil;
import com.haoze.nurseapp.dao.AtomizeMedReturnMapper;
import com.haoze.nurseapp.dao.PatientMapper;
import com.haoze.nurseapp.dao.TaskExecuteMapper;
import com.haoze.nurseapp.enumeration.AtomizeMedEnum;
import com.haoze.nurseapp.enumeration.ConstsEnum;
import com.haoze.nurseapp.enumeration.OralEnum;
import com.haoze.nurseapp.enumeration.VarCodeEnum;
import com.haoze.nurseapp.model.AtomizeMedReturnEntity;
import com.haoze.nurseapp.service.AtomizeMedService;
import org.apache.commons.lang.StringUtils;
import org.quartz.CronExpression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: Chenchao
 * @CreateTime: 2020-11-25 08:27
 */
@Service
public class AtomizeMedServiceImpl implements AtomizeMedService {

    private static final Logger logger = LoggerFactory.getLogger(AtomizeMedServiceImpl.class);
    private static final SimpleDateFormat yyyymmddhhmmss = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    @Autowired
    private TaskExecuteMapper taskExecuteMapper;
    @Autowired
    private CommonUtils commonUtils;
    @Autowired
    private TaskExecuteServiceImpl taskExecuteServiceImpl;
    @Autowired
    private PatientMapper patientMapper;
    @Autowired
    private AtomizeMedReturnMapper atomizeMedReturnMapper;


    @Override
    public Result taskList(String wardId, String type, String date, String queryString, Integer page, Integer pageSize) {
        //查询全部时 直接查询表里的数据
        if (StringUtils.isEmpty(date) && (AtomizeMedEnum.TYPE_FIVE.getIndex().equals(type) || AtomizeMedEnum.TYPE_SIX.getIndex().equals(type))) {
            PageHelper.startPage(page, pageSize);
            List<Map<String, Object>> allReturn = atomizeMedReturnMapper.queryByWardId(wardId, type);
            allReturn.stream().forEach(map -> {
                try {
                    //暂时先用这种方法处理执行时间，后续如果其他类型也需要这样显示 需要另外想方法
                    String[] qrCodes = map.get("qrCode").toString().split("_");
                    String executeTimeStr = qrCodes[1].substring(qrCodes[1].length() - 14);
                    Date executeTime = DateUtil.stringToDate(executeTimeStr, "yyyyMMddHHmmss");
                    String execTimeStr = DateUtil.dateToString(executeTime, "yyyy-MM-dd HH:mm:ss");
                    map.put("execDate", execTimeStr);
                } catch (Exception e) {
                    map.put("execDate", DateUtil.dateToString(new Date(), "yyyy-MM-dd HH:mm:ss"));
                }
            });

            PageInfo pageInfo = new PageInfo<>(allReturn);
            return ResultGenerator.genOkResult(pageInfo);
        }
        List<Map<String, Object>> qrCodeList = new ArrayList<>();
        List<Map<String, Object>> patients = patientMapper.queryPatients(wardId, queryString);
        String inpatNums = patients.stream().map(obj -> obj.get("inpatNum").toString()).collect(Collectors.joining(","));
        String beginTime = date + " 00:00";
        String endTime = date + " 23:59";
        List<String> staticWardList = taskExecuteMapper.queryStaticAllocationWard(VarCodeEnum.SYLCZX.getVarCode());
        List<Map<String, Object>> list = taskExecuteMapper.orderQRCodeNew(inpatNums, beginTime, endTime, OralEnum.ATOMIZE.getName(), "",staticWardList);
        list.stream().forEach(result -> {
            commonUtils.computeAge(result);
            List<Map<String, Object>> orderList = taskExecuteMapper.queryOrdersByInpatNum(result.get("inpatNum").toString(), result.get("orderNo").toString());
            try {
                this.createFreQrCode(qrCodeList, result, date, orderList, type);
            } catch (Exception e) {
                logger.error("获取失败", e);
            }
        });
        PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(qrCodeList.stream().skip((page - 1) * pageSize).limit(pageSize).collect(Collectors.toList()));
        pageInfo.setTotal(qrCodeList.size());
        return ResultGenerator.genOkResult(pageInfo);
    }

    @Override
    public Result numList(String wardId, String date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        if (StringUtils.isBlank(date)) {
            date = sdf.format(new Date());
        }
        Map<String, Integer> finalResult = new HashMap<>();
        List<Map<String, Object>> patients = patientMapper.queryPatients(wardId, "");
        String inpatNums = patients.stream().map(obj -> obj.get("inpatNum").toString()).collect(Collectors.joining(","));
        String beginTime = date + " 00:00";
        String endTime = date + " 23:59";
        List<String> staticWardList = taskExecuteMapper.queryStaticAllocationWard(VarCodeEnum.SYLCZX.getVarCode());
        List<Map<String, Object>> list = taskExecuteMapper.orderQRCodeNew(inpatNums, beginTime, endTime, OralEnum.ATOMIZE.getName(), "",staticWardList);
        for (AtomizeMedEnum enumTemp : AtomizeMedEnum.values()) {
            List<Map<String, Object>> qrCodeList = new ArrayList<>();
            String finalDate = date;
            list.stream().forEach(result -> {
                List<Map<String, Object>> orderList = taskExecuteMapper.queryOrdersByInpatNum(result.get("inpatNum").toString(), result.get("orderNo").toString());
                try {
                    this.createFreQrCode(qrCodeList, result, finalDate, orderList, enumTemp.getIndex());
                } catch (Exception e) {
                    logger.error("获取失败", e);
                }
            });
            finalResult.put(enumTemp.getIndex(), qrCodeList.size());
        }
        return ResultGenerator.genOkResult(finalResult);
    }


    private List<Map<String, Object>> createFreQrCode(List<Map<String, Object>> qrCodeList, Map<String, Object> result, String date, List<Map<String, Object>> orderList, String type) throws ParseException {
        String executeDateStr = date.replaceAll("-", "");
        Date executeDate = DateUtil.stringToDate(executeDateStr, "yyyyMMdd");
        Date executeEndDateTime = DateUtil.getDateAfter(DateUtil.stringToDate(executeDateStr, "yyyyMMdd"), 1);
        //  临时医嘱
        if (org.apache.commons.lang.StringUtils.isEmpty((String) result.get("TIMEMODE")) || result.get("orderType").equals("2")) {
            Date beginDateTime = DateUtil.stringToDate(result.get("planBeginDatetime").toString(), "yyyy-MM-dd HH:mm:ss");
            String begindateTimeFormat1 = DateUtil.dateToString(beginDateTime, "yyyyMMddHHmmss");
            String begindateTimeFormat2 = DateUtil.dateToString(beginDateTime, "yyyy-MM-dd HH:mm:ss");
            String oralCode = new StringBuffer("y_").append(result.get("medicalNum")).append(begindateTimeFormat1).append("_").append(result.get("orderNo")).toString();
            this.confirmAdd(qrCodeList, result, oralCode, begindateTimeFormat2, orderList, type);
        } else if (result.get("TIMEMODE").equals("0")) {
            Date beginDateTime = DateUtil.stringToDate(result.get("planBeginDatetime").toString(), "yyyy-MM-dd HH:mm:ss");
            //如果指定时间的0点小于开始时间，则使用开始时间计算
            Date startTime = executeDate;
            Date eTime = null;
            if (result.get("planEndDatetime") != null) {
                eTime = yyyymmddhhmmss.parse((String) result.get("planEndDatetime"));
            }
            Date endTime = result.get("planEndDatetime") == null ? executeEndDateTime : (eTime.compareTo(executeEndDateTime) >= 0 ? executeEndDateTime : eTime);
            CronDescriber cronDescriber = JSONObject.parseObject((String) result.get("CRON_DESCRIBER"), CronDescriber.class);
            String expression = CronUtil.createCronExpression(cronDescriber, null);
            CronExpression cronExpression = null;
            try {
                cronExpression = new CronExpression(expression);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            startTime = cronExpression.getNextValidTimeAfter(startTime);
            /*if (startTime.equals(DateUtil.getDateAfter(beginDateTime, 1)) || startTime.after(executeEndDateTime)) {//执行时间与创建时间一致.非间隔时间表达式会不包含.会向前推一天,需要判断后手动回
                startTime = DateUtil.getDateBefore(startTime, 1);
            }*/
            while (startTime.before(executeEndDateTime) && (null == result.get("planEndDatetime") || startTime.before(endTime))) {
                String oralCode = new StringBuffer("y_").append(result.get("medicalNum")).append(new SimpleDateFormat("yyyyMMddHHmmss").format(startTime)).append("_").append(result.get("orderNo")).toString();
                if (!startTime.before(beginDateTime)) {
                    this.confirmAdd(qrCodeList, result, oralCode, yyyymmddhhmmss.format(startTime), orderList, type);
                }
                startTime = cronExpression.getNextValidTimeAfter(startTime);
            }
        } else {
            Date beginDateTime = DateUtil.stringToDate(result.get("planBeginDatetime").toString(), "yyyy-MM-dd HH:mm:ss");
            Date beginDate = DateUtil.stringToDate(result.get("planBeginDatetime").toString(), "yyyy-MM-dd");
            //如果指定时间的0点小于开始时间，则使用开始时间计算
            Date startTime = executeDate.equals(beginDate) ? beginDateTime : DateUtil.getDateAfterRedSecond(executeDate, 1);
            Date eTime = null;
            if (result.get("planEndDatetime") != null) {
                eTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse((String) result.get("planEndDatetime"));
            }
            Date endTime = result.get("planEndDatetime") == null ? executeEndDateTime : (eTime.compareTo(executeEndDateTime) >= 0 ? executeEndDateTime : eTime);
            CronDescriber cronDescriber = JSONObject.parseObject((String) result.get("CRON_DESCRIBER"), CronDescriber.class);
            String expression = CronUtil.createCronExpression(cronDescriber, null);
            CronExpression cronExpression = null;
            try {
                cronExpression = new CronExpression(expression);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            if (startTime.equals(beginDateTime) && result.get("TIMEMODE").equals("1")) {
                startTime = executeDate;
            }
            startTime = cronExpression.getNextValidTimeAfter(startTime);
            /*if (startTime.equals(DateUtil.getDateAfter(beginDateTime, 1)) || startTime.after(executeEndDateTime)) {//执行时间与创建时间一致.非间隔时间表达式会不包含.会向前推一天,需要判断后手动回
                startTime = DateUtil.getDateBefore(startTime, 1);
            }*/
            while (startTime.before(executeEndDateTime) && (null == result.get("planEndDatetime") || startTime.before(endTime))) {
                String oralCode = new StringBuffer("y_").append(result.get("medicalNum")).append(new SimpleDateFormat("yyyyMMddHHmmss").format(startTime)).append("_").append(result.get("orderNo")).toString();
                if (!startTime.before(beginDateTime)) {
                    this.confirmAdd(qrCodeList, result, oralCode, yyyymmddhhmmss.format(startTime), orderList, type);
                }
                startTime = DateUtil.increasedSeconds(startTime, Integer.parseInt((String) result.get("exeCycleStamp")));
            }
        }
        return qrCodeList;
    }

    private void confirmAdd(List<Map<String, Object>> qrCodeList, Map<String, Object> result, String oralCode, String beginTimeFormat, List<Map<String, Object>> orderList, String type) {
        String nodeName = taskExecuteMapper.queryCurrentNodeName(oralCode);
        for (AtomizeMedEnum enumTemp : AtomizeMedEnum.values()) {
            if (type.equals(enumTemp.getIndex())) {
                if (enumTemp.getIndex().equals(AtomizeMedEnum.TYPE_ONE.getIndex())) {
                    if (enumTemp.getNodeName().equals(nodeName) || StringUtils.isBlank(nodeName)) {
                        Map<String, String> backInfo = taskExecuteMapper.queryBackInfo(oralCode, ConstsEnum.ATOMIZE_MED_RETURN_TWO.getIndex());
                        if (backInfo == null) {
                            Map<String, Object> newResult = new HashMap<>();
                            newResult.put("qrCode", oralCode);
                            newResult.put("execDate", beginTimeFormat);
                            newResult.put("orderList", orderList);
                            this.addKey(newResult, result);
                            qrCodeList.add(newResult);
                        }
                    }
                } else if (enumTemp.getIndex().equals(AtomizeMedEnum.TYPE_FIVE.getIndex())) {
                    //查询是否回收 回收直接查询表的数据 任务当前节点会返回待给药
                    Map<String, String> backInfo = taskExecuteMapper.queryBackInfo(oralCode, ConstsEnum.ATOMIZE_MED_RETURN_ONE.getIndex());
                    if (backInfo != null) {
                        Map<String, Object> newResult = new HashMap<>();
                        newResult.put("qrCode", oralCode);
                        newResult.put("execDate", beginTimeFormat);
                        newResult.put("orderList", orderList);
                        newResult.put("returnRemark", backInfo.get("returnRemark"));
                        newResult.put("returnTime", backInfo.get("returnTime"));
                        newResult.put("returnPerson", backInfo.get("returnPerson"));
                        this.addKey(newResult, result);
                        qrCodeList.add(newResult);
                    }
                } else if (enumTemp.getIndex().equals(AtomizeMedEnum.TYPE_SIX.getIndex())) {
                    Map<String, String> backInfo = taskExecuteMapper.queryBackInfo(oralCode, ConstsEnum.ATOMIZE_MED_RETURN_TWO.getIndex());
                    if (backInfo != null) {
                        Map<String, Object> newResult = new HashMap<>();
                        newResult.put("qrCode", oralCode);
                        newResult.put("execDate", beginTimeFormat);
                        newResult.put("orderList", orderList);
                        newResult.put("returnRemark", backInfo.get("returnRemark"));
                        newResult.put("returnTime", backInfo.get("returnTime"));
                        newResult.put("returnPerson", backInfo.get("returnPerson"));
                        this.addKey(newResult, result);
                        qrCodeList.add(newResult);
                    }
                } else {
                    if (enumTemp.getNodeName().equals(nodeName)) {
                        Map<String, Object> newResult = new HashMap<>();
                        newResult.put("qrCode", oralCode);
                        newResult.put("execDate", beginTimeFormat);
                        newResult.put("orderList", orderList);
                        this.addKey(newResult, result);
                        qrCodeList.add(newResult);
                    }
                }
                break;
            }
        }
    }

    private Map<String, Object> addKey(Map<String, Object> newResult, Map<String, Object> result) {
        newResult.put("patName", result.get("patName"));
        newResult.put("sex", result.get("sex"));
        newResult.put("bedNo", result.get("bedNo"));
        newResult.put("bedLabel", result.get("bedLabel"));
        newResult.put("age", result.get("age"));
        newResult.put("medicalNum", result.get("medicalNum"));
        newResult.put("inpatOrderId", result.get("inpatOrderId"));
        return newResult;
    }


    @Override
    public Result stopTask(AtomizeMedReturnEntity atomizeMedReturn) {
        String userId = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getHeader("zuul_id");
        atomizeMedReturn.setInpatNum(atomizeMedReturn.getInpatNum() + "-1");
        Map<String, String> patientInfo = patientMapper.queryPatientInfo(atomizeMedReturn.getInpatNum());
        AtomizeMedReturnEntity atomizeMedReturnEntity = new AtomizeMedReturnEntity();
        BeanUtils.copyProperties(atomizeMedReturn, atomizeMedReturnEntity);
        atomizeMedReturnEntity.initAdd();
        atomizeMedReturnEntity.setReturnId(UUIDUtil.randomString());
        atomizeMedReturnEntity.setDeptId(patientInfo.get("deptId"));
        atomizeMedReturnEntity.setWardDeptId(patientInfo.get("wardDeptId"));
        atomizeMedReturnEntity.setReturnTime(new Timestamp(System.currentTimeMillis()));
        atomizeMedReturnEntity.setReturnUserId(userId);
        atomizeMedReturnEntity.setDelFlag(ConstsEnum.DEFAULT_NO.getIndex());
        atomizeMedReturnEntity.setType(ConstsEnum.ATOMIZE_MED_RETURN_TWO.getIndex());
        atomizeMedReturnMapper.insert(atomizeMedReturnEntity);
        return ResultGenerator.genOkResult();
    }

}
